import { useRequest } from 'ahooks'
import { FormInstance, Pagination, Table } from 'antd'
import { useEffect, useRef } from 'react'
import './TablePage.less'
import {
  BasicCard,
  SearchForm,
  SearchFormRef,
  StretchTableBox,
  Toolbar,
  useTableState,
  useRowSelection,
} from '@/components'
import { Pagination as PaginationType, Pageable, Response } from '@/types'
import { TablePageProps } from '@/components'

/**
 * 一个标准的列表页
 */
export const TablePage = (props: TablePageProps) => {
  const {
    queryProps,
    toolbar,
    tableProps,
    api = () => Promise.resolve({} as Response<PaginationType<any>>),
    beforeRequest,
    beforeResponse,
    autoSearch = true,
    useLoading = true,
    children,
  } = props

  // 状态
  const {
    dataSource,
    setDataSource,
    selectedRowKeys,
    setSelection,
    pagination,
    setPagination,
  } = useTableState()
  // 选择配置
  const { rowSelection } = useRowSelection(
    selectedRowKeys,
    setSelection,
    tableProps?.rowSelection
  )
  // 查询组件实例
  const searchFormRef = useRef<SearchFormRef>(null)

  // 请求包装Hook
  // 初始化时不能自动调用api，需要由页面触发请求，这样才会正确获取数据
  const request = useRequest(api, { manual: true })

  /**
   * 执行查询逻辑
   * - 清空选择项
   * @param params 参数
   * @param form 表单实例
   * @param pageable 分页参数
   */
  const executeSearch = async (
    params: any,
    form: FormInstance<any>,
    pageable?: Pageable
  ) => {
    // 查询前处理参数
    if (beforeRequest) {
      params = beforeRequest(params, form)
    }
    const newPageable: Pageable = {
      pageNumber: pagination.pageNumber,
      pageSize: pagination.pageSize,
      ...pageable,
    }
    let res = await request.runAsync?.(params, newPageable)
    // 查询后处理响应
    if (beforeResponse) {
      res = beforeResponse(res?.data, form)
    }
    const { records = [], total = 0 } = res?.data ?? {}
    // 设置数据源
    setDataSource(records)
    // 设置分页总数
    setPagination({ total: total })
    // 清空选择项
    setSelection([], [])

    return Promise.resolve()
  }

  /**
   * 查询按钮点击
   * - 切换到第1页
   * - 清空选择项
   * @param form 表单实例
   */
  const handleSearch = async (form: FormInstance) => {
    // 校验查询参数是否填写完整
    const params = await form.validateFields()
    // 分页器切换到第1页
    setPagination({ pageNumber: 1 })
    // 执行查询逻辑，条件切换到第1页
    await executeSearch(params, form, {
      pageNumber: 1,
      pageSize: pagination.pageSize,
    })
  }

  /**
   * 分页切换时重新查询
   * - 不切换到第1页
   * - 清空选择项
   * @param pageNumber 第几页
   * @param pageSize 分页大小
   */
  const handlePageChange = async (
    pageNumber: number = pagination.pageNumber,
    pageSize: number = pagination.pageSize
  ) => {
    const { form, validateFields } = searchFormRef.current!
    // 获取表单字段，若校验出错，后续将不会执行
    const params = await validateFields()
    // 分页器切换到指定分页、大小
    setPagination({ pageNumber, pageSize })
    // 执行查询逻辑
    await executeSearch(params, form, { pageNumber, pageSize })
  }

  // 进入页面时初始化数据
  useEffect(() => {
    if (autoSearch && searchFormRef.current) {
      // 通过查询组件提供的方法触发重查
      handleSearch(searchFormRef.current.form)
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  return (
    <>
      <div className="page table-list-page">
        {queryProps && (
          <BasicCard container={false} className="page-query">
            <SearchForm
              ref={searchFormRef}
              items={queryProps.items}
              onSearch={handleSearch}
            />
          </BasicCard>
        )}
        <BasicCard container={false} className="page-content">
          <StretchTableBox
            topComponent={<Toolbar {...toolbar} />}
            ignoreHeight={[16, 45, 55, 8]}
          >
            <Table
              bordered
              {...tableProps}
              rowSelection={rowSelection}
              dataSource={dataSource}
              pagination={{
                position: ['none'],
                ...pagination,
              }}
              loading={useLoading ? request.loading : false}
            />
          </StretchTableBox>
        </BasicCard>
        <BasicCard padding={false} className="page-footer">
          <Pagination
            current={pagination.pageNumber}
            pageSize={pagination.pageSize}
            total={pagination.total}
            onChange={handlePageChange}
            showTotal={(total) => `总 ${total} 条`}
          />
        </BasicCard>
      </div>
      {children}
    </>
  )
}
